package com.hyt.it.ogt.kq.service.gov.service.impl;

import java.io.File;
import java.nio.charset.Charset;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import com.hyt.core.base.BaseEntity;
import com.hyt.it.ogt.kq.service.gov.den.ArrangedResultExportUtil;
import com.hyt.it.ogt.kq.service.gov.mapper.*;
import com.hyt.it.ogt.kq.service.gov.model.entity.*;
import com.hyt.it.ogt.kq.service.model.entity.Subject;
import com.hyt.loginfo.model.User;
import com.linuxense.javadbf.DBFField;
import com.linuxense.javadbf.DBFWriter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.exception.NestedBusinessException;
import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.exception.DataBeingLockedException;
import com.hyt.it.ogt.kq.common.gov.constant.CodeEnum;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.constant.StringCodeEnum;
import com.hyt.it.ogt.kq.common.gov.constant.TaskExamTypeEnum;
import com.hyt.it.ogt.kq.common.gov.enums.TaskKsConfigCode;
import com.hyt.it.ogt.kq.common.gov.utils.DateTimeUtil;
import com.hyt.it.ogt.kq.service.gov.feign.ks.KsClient;
import com.hyt.it.ogt.kq.service.gov.feign.ks.model.PushCandidateNoticeParam;
import com.hyt.it.ogt.kq.service.gov.feign.ks.model.PushHelloParam;
import com.hyt.it.ogt.kq.service.gov.feign.ks.model.PushTimeParam;
import com.hyt.it.ogt.kq.service.gov.feign.ks.model.PushTimeTaskParam;
import com.hyt.it.ogt.kq.service.gov.model.dto.TimeInfoResultDTO;
import com.hyt.it.ogt.kq.service.gov.model.param.TaskOnLineConfig;
import com.hyt.it.ogt.kq.service.gov.model.param.TimeParam;
import com.hyt.it.ogt.kq.service.gov.model.vo.OfficeRoomVO;
import com.hyt.it.ogt.kq.service.gov.model.vo.SubjectInfoVO;
import com.hyt.it.ogt.kq.service.gov.model.vo.TaskTimeInfoVO;
import com.hyt.it.ogt.kq.service.gov.model.vo.overview.ExamMonitorCollectVO;
import com.hyt.it.ogt.kq.service.gov.service.IExamAgreementService;
import com.hyt.it.ogt.kq.service.gov.service.ISysFileService;
import com.hyt.it.ogt.kq.service.gov.service.ITaskKsConfigService;
import com.hyt.it.ogt.kq.service.gov.service.ITaskService;
import com.hyt.it.ogt.kq.service.gov.service.ITimeRoomCandidateService;
import com.hyt.it.ogt.kq.service.gov.service.ITimeRoomService;
import com.hyt.it.ogt.kq.service.gov.service.ITimeService;
import com.hyt.it.ogt.kq.service.gov.service.ITimeSubjectPaperService;
import com.hyt.it.ogt.kq.service.gov.service.ITimeSubjectService;

import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 批次信息表 服务实现类
 * </p>
 *
 * @author huangyh
 * @since 2021-03-08
 */
@Service
@Slf4j
public class TimeServiceImpl extends BaseServiceImpl<TimeMapper, Time> implements ITimeService {

    @Resource
    private ITimeRoomCandidateService iTimeRoomCandidateService;
    @Resource
    private ITimeSubjectService iTimeSubjectService;
    @Resource
    private ITimeSubjectPaperService iTimeSubjectPaperService;
    @Resource
    private TimeSubjectMapper timeSubjectMapper;
    @Resource
    private ITimeRoomService iTimeRoomService;
    @Resource
    private ITaskService iTaskService;
    @Resource
    private IExamAgreementService iExamAgreementService;
    @Resource
    private ITaskKsConfigService iTaskKsConfigService;
    @Resource
    private KsClient ksClient;
    @Resource
    private TimeRoomMapper timeRoomMapper;
    @Resource
    private ISysFileService iSysFileService;
    @Resource
    private SubjectMapper subjectMapper;
    @Resource
    private TaskRoomMapper taskRoomMapper;
    @Resource
    ArrangedResultExportUtil arrangedResultExportUtil;

    @Override
    @Transactional(noRollbackFor = DataBeingLockedException.class)
    public void addOrUpdate(TimeParam timeParam, User user) throws Exception {
        //参数校验
        this.verifyTimeSubject(timeParam);
        //线上或线下机考参数校验
        Task task = iTaskService.getTaskById(timeParam.getTaskId());
        switch (TaskExamTypeEnum.getByCode(task.getExamType())) {
            //线上编排参数校验
            case ONLINE:
                this.validOnlineTimeSubject(timeParam, task);
                break;
            //线下编排参数校验
            case OFFLINE:
                this.verifyOfflineTimeSubject();
                break;
        }
        //验证线下模式批次科目数据
        //validOnlineTimeSubject(timeParam, task);
        //获取参数中timeId
        boolean isAdd = StringUtils.isBlank(timeParam.getTimeId());
        //批次参数校验，生成批次编号
        Time time = this.checkTimeParam(timeParam);
        time.setOfficeId(user.getOfficeid());
        time.setDeptId(user.getOrganizationid());
        //判断是否保存
        if (isAdd) {
            saveTime(timeParam, time, task);
        } else {
            updateTime(timeParam, time, task);
        }
    }

    /**
     * 批次科目参数校验
     * @param timeParam 批次科目参数
     */
    private void verifyTimeSubject(TimeParam timeParam) {
        LocalDateTime startTime = timeParam.getStartTime();
        //校验批次开始时间

        //校验批次开始和结束时间
        LocalDateTime endTime = timeParam.getEndTime();
        if (startTime.equals(endTime)) {
            //批次开始时间不能等于批次结束时间
            throw new KqException(ResponseCode.TIME_START_TIME_MUST_NOT_BE_EQUALS_END_TIME.getCode(),
                    ResponseCode.TIME_START_TIME_MUST_NOT_BE_EQUALS_END_TIME.getMsg());
        }
        if (startTime.isAfter(endTime)) {
            //批次开始时间不能晚于批次结束时间
            throw new KqException(ResponseCode.TIME_START_TIME_MUST_BE_BEFORE_END_TIME.getCode(),
                    ResponseCode.TIME_START_TIME_MUST_BE_BEFORE_END_TIME.getMsg());
        }
        //其他校验...
    }

    private void verifyOfflineTimeSubject() {
        // 线下编排参数校验
    }

    /**
     * 线上模式，校验批次科目，只允许有一个科目,而且一个科目只能存在于一个批次中。
     * @param timeParam
     */
    private void validOnlineTimeSubject(TimeParam timeParam,Task task) {

        //1。不允许多科
        /*String subjects = timeParam.getSubjectIds();
        if(subjects.split(",").length > 1) {
            throw new KqException(ResponseCode.TIMES_ONLINE_ONE_SUBJECT.getCode(),
                    ResponseCode.TIMES_ONLINE_ONE_SUBJECT.getMsg());
        }*/

        String subjects = timeParam.getSubjectIds();
        //2。一个科目不允许存在于多个批次
        Boolean flag = iTimeSubjectService.existTimeSubject(task.getId(),subjects,timeParam.getTimeId());
        if (flag) {
            throw new KqException(ResponseCode.TIMES_ONLINE_TIME_SUBJECT_EXIST.getCode(),
                    ResponseCode.TIMES_ONLINE_TIME_SUBJECT_EXIST.getMsg());
        }

        //3.考生须知和欢迎语是否为空
        iExamAgreementService.existNullExamAgreement(task.getId());

        //4.跨天验证
        if ((timeParam.getEndTime().getDayOfMonth() - timeParam.getStartTime().getDayOfMonth()) != 0) {

            List<TaskOnLineConfig>  taskOnLineConfigList = iTaskKsConfigService.getTaskOnLineConfigByTaskId(task.getId());
            taskOnLineConfigList.stream().forEach(taskOnLineConfig -> {
                // 提前登陆  检测所有批次不能夸天
                if (TaskKsConfigCode.EXAM_CONFIG_CODE_EARLYLOGON.getCode().equals(taskOnLineConfig.getConfigCode()) && TaskKsConfigCode.EXAM_CONFIG_CODE_ON.getCode().equals(taskOnLineConfig.getConfigValue())) {
                    throw new KqException(ResponseCode.TIMES_ONLINE_TIME_DAY_EARLYLOGON.getCode(),
                            ResponseCode.TIMES_ONLINE_TIME_DAY_EARLYLOGON.getMsg());
                }

                // 限制迟到  检测所有批次不能夸天
                if (TaskKsConfigCode.EXAM_CONFIG_CODE_DELAYLOGON.getCode().equals(taskOnLineConfig.getConfigCode()) && TaskKsConfigCode.EXAM_CONFIG_CODE_ON.getCode().equals(taskOnLineConfig.getConfigValue())) {
                    throw new KqException(ResponseCode.TIMES_ONLINE_TIME_DAY_DELAYLOGON.getCode(),
                            ResponseCode.TIMES_ONLINE_TIME_DAY_DELAYLOGON.getMsg());
                }

                // 统一开考  检测所有批次不能夸天
                if (TaskKsConfigCode.EXAM_CONFIG_CODE_UNIFIEDSTARTEND.getCode().equals(taskOnLineConfig.getConfigCode()) && TaskKsConfigCode.EXAM_CONFIG_CODE_ON.getCode().equals(taskOnLineConfig.getConfigValue())) {
                    throw new KqException(ResponseCode.TIMES_ONLINE_TIME_DAY_UNIFIEDSTARTEND.getCode(),
                            ResponseCode.TIMES_ONLINE_TIME_DAY_UNIFIEDSTARTEND.getMsg());
                }
            });
        }
    }

    /**
     * 批次科目是否已编排
     * @param timeId
     * @return
     */
    boolean checkTimeSubjectIsArrange(String timeId){
        Time time = this.baseMapper.selectOne(new LambdaQueryWrapper<Time>().eq(Time::getId, timeId));
        //如果批次科目已编排不允许操作
        List<TimeRoomCandidate> timeRoomCandidates = iTimeRoomCandidateService.getBaseMapper().selectList(new LambdaQueryWrapper<TimeRoomCandidate>()
                .eq(TimeRoomCandidate::getTaskId, time.getTaskId())
                .eq(TimeRoomCandidate::getTimeId, time.getId())
                .eq(TimeRoomCandidate::getDelFlag, false));
        return !CollectionUtils.isEmpty(timeRoomCandidates);
    }

    private void saveTime(TimeParam timeParam,Time time,Task task) {

        //校验数据锁定
        if (task.getDataLock()) {
            throw new KqException(ResponseCode.TASK_DATA_LOCK_TRUE.getCode(),"数据已锁定，不允许操作此功能。");
        }

        //插入批次
        time.setStartTime(timeParam.getStartTime())
                .setEndTime(timeParam.getEndTime())
                .setId(UUIDUtils.newSortUUID());
        this.save(time);

        //插入批次科目
        if(StringUtils.isNotBlank(timeParam.getSubjectIds())){
            String[] subjects = timeParam.getSubjectIds().split(",");
            for (int i = 0; i < subjects.length; i++) {
                String subjectId = subjects[i];
                TimeSubject timeSubject = new TimeSubject();
                timeSubject.setTaskId(timeParam.getTaskId())
                        .setTimeId(time.getId())
                        .setSubjectId(subjectId)
                        .setId(UUIDUtils.newSortUUID());

                timeSubjectMapper.insert(timeSubject);
            }
        }
        //推送数据到考试
        pushTimeParam(task,time,StringCodeEnum.PUSH_TYPE_INSERT.getCode());
    }


    /**
     * 批次推送参数
     * @param task
     * @param time
     * @param type
     * @return
     */
    private void pushTimeParam(Task task, Time time, String type) {

        if (TaskExamTypeEnum.OFFLINE.getCode().equals(task.getExamType())) {
            return;
        }

        PushTimeTaskParam pushTimeTaskParam = new PushTimeTaskParam();

        //批次数据
        PushTimeParam pushTimeParam = new PushTimeParam();
        BeanUtils.copyProperties(time,pushTimeParam);
        pushTimeParam.setTimeId(time.getId())
                .setOfficeId(task.getOfficeId())
                .setStartTime(DateTimeUtil.getDateTimeString(time.getStartTime()))
                .setEndTime(DateTimeUtil.getDateTimeString(time.getEndTime()))
                .setTaskId(task.getId());

        pushTimeTaskParam.setTaskId(task.getId())
                .setTaskName(task.getName())
                .setPushTimeParam(pushTimeParam)
                .setPushType(type);

        //只有新增才会有下面的数据
        if (StringCodeEnum.PUSH_TYPE_INSERT.getCode().equals(type)) {

            //查询任务参数
            pushTimeTaskParam.setExamConfigs(iTaskKsConfigService.getExamConfigNoFalse(task.getId()));

            //考生须知，欢迎语
            List<ExamAgreement>  examAgreements = iExamAgreementService.getExamAgreementList(task.getId());
            examAgreements.stream().forEach(examAgreement -> {
                if (CodeEnum.EXAM_AGREEMENT_CANDIDATE_NOTICE.getCode().equals(examAgreement.getType())) {

                    SysFile sysFile = iSysFileService.getSysFileById(examAgreement.getContent());

                    //查询考生须知
                    PushCandidateNoticeParam pushCandidateNoticeParam = new PushCandidateNoticeParam();
                    pushCandidateNoticeParam.setTaskId(examAgreement.getTaskId())
                            .setContent(sysFile.getUrl());

                    pushTimeTaskParam.setPushCandidateNoticeParam(pushCandidateNoticeParam);
                } else if(CodeEnum.EXAM_AGREEMENT_HELLO.getCode().equals(examAgreement.getType())) {
                    //查询欢迎语
                    PushHelloParam pushHelloParam = new PushHelloParam();
                    pushHelloParam.setTaskId(examAgreement.getTaskId())
                            .setContent(examAgreement.getContent());
                    pushTimeTaskParam.setPushHelloParam(pushHelloParam);
                }
            });
        }

        //推送数据
        ApiResponse<Object> res = ksClient.pushTime(pushTimeTaskParam);

        if (res == null) {
            throw new KqException(ResponseCode.TIMES_PUSH_RESULT_NONE.getCode(),
                    ResponseCode.TIMES_PUSH_RESULT_NONE.getMsg());
        }

        if (!ResponseCode.SUCCESS.getCode().equals(res.getCode())) {
            throw new KqException(res.getCode(),"调用考试接口失败。");
        }
        log.info("推送数据成功后返回内容，{}",res.getData());
        //保存考试id
        if (StringCodeEnum.PUSH_TYPE_INSERT.getCode().equals(type) && res.getData() != null) {
            this.baseMapper.insertTimeExamCode(UUIDUtils.newSortUUID(), task.getId(),time.getId(), res.getData().toString());
        }
    }

    private void updateTime(TimeParam timeParam, Time time, Task task) throws Exception {
        if (TaskExamTypeEnum.OFFLINE.getCode().equals(task.getExamType())) {
            //线下机考校验数据锁定
            if (task.getDataLock()) {
                throw new KqException(ResponseCode.TASK_DATA_LOCK_TRUE.getCode(),
                        "数据已锁定，不允许操作此功能。");
            }
        }
        //线上机考不校验数据锁定，强行修改批次信息
        //获取当前批次科目信息
        LambdaQueryWrapper<TimeSubject> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(TimeSubject::getDelFlag,false)
                .eq(TimeSubject::getTaskId, timeParam.getTaskId())
                .eq(TimeSubject::getTimeId, timeParam.getTimeId());
        List<TimeSubject> timeSubjectList = timeSubjectMapper.selectList(queryWrapper);
        //获取当前批次编排情况
        boolean arranged = iTimeRoomCandidateService.hasArranged(timeParam.getTaskId(), timeParam.getTimeId());
        if (arranged) {
            //当前批次已编排的情况下，不修改批次科目信息
            String subjectIds = timeSubjectList.stream()
                    .map(TimeSubject::getSubjectId)
                    .collect(Collectors.joining(","));
            timeParam.setSubjectIds(subjectIds);
        }
        //更新批次信息
        time.setId(timeParam.getTimeId());
        this.updateById(time);
        //更新批次科目信息
        /*StringBuffer buffer = new StringBuffer();
        timeSubjectList.stream().forEach(timeSubject -> {
            if (!timeParam.getSubjectIds().contains(timeSubject.getSubjectId())) {
                //删除批次科目
                timeSubjectMapper.deleteById(timeSubject.getId());
            }
            buffer.append(timeSubject.getSubjectId()).append(",");
        });
        if(StringUtils.isNotBlank(timeParam.getSubjectIds())){
            String[] subjects = timeParam.getSubjectIds().split(",");
            for (String subjectId : subjects) {
                if (!buffer.toString().contains(subjectId)) {
                    TimeSubject timeSubject = new TimeSubject();
                    timeSubject.setTaskId(timeParam.getTaskId())
                            .setTimeId(time.getId())
                            .setSubjectId(subjectId)
                            .setId(UUIDUtils.newSortUUID());
                    //批次科目插入
                    timeSubjectMapper.insert(timeSubject);
                }
            }
        }*/
        //推送数据到考试
        pushTimeParam(task, time, StringCodeEnum.PUSH_TYPE_UPDATE.getCode());
        //当前批次已编排，抛出异常提示前端
        if (arranged) {
            //当前批次已存在编排数据，仅修改除考试科目以外的信息
            throw new DataBeingLockedException(ResponseCode.TIME_ARRANGED.getCode(),
                    ResponseCode.TIME_ARRANGED.getMsg());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTimeOrSubject(String timeId)  {
        Time time = baseMapper.selectById(timeId);
        String taskId = time.getTaskId();
        //如果已经编排，则不允许删除。
        Task task = iTaskService.lambdaQuery()
                .eq(Task::getId,taskId)
                .last("LIMIT 1")
                .one();

        if (task.getDataLock()) {
            throw new KqException(ResponseCode.TASK_DATA_LOCK_TRUE.getCode(),"数据已锁定，不允许操作此功能。");
        }

        LambdaQueryWrapper<TimeRoom> timeRoomLambdaQueryWrapper = Wrappers.lambdaQuery();
        timeRoomLambdaQueryWrapper.eq(TimeRoom::getTaskId,taskId)
                .eq(TimeRoom::getTimeId,timeId)
                .gt(TimeRoom::getActualCount,0)
                .eq(TimeRoom::getDelFlag,false);
        TimeRoom timeRoom = iTimeRoomService.getOne(timeRoomLambdaQueryWrapper);
        if (timeRoom != null) {
            throw new KqException(ResponseCode.TIMES_CAN_NOT_REMOVE.getCode(),
                    ResponseCode.TIMES_CAN_NOT_REMOVE.getMsg());
        }

        Integer count = iTimeSubjectPaperService.lambdaQuery()
                .eq(TimeSubjectPaper::getTaskId,taskId)
                .eq(TimeSubjectPaper::getTimeId,timeId)
                .eq(TimeSubjectPaper::getDelFlag,false)
                .isNotNull(TimeSubjectPaper::getPaperId)
                .count();
        if (count > 0) {
            throw new KqException(ResponseCode.TIMES_IS_BIND_PAPER_CAN_NOT_REMOVE.getCode(),
                    ResponseCode.TIMES_IS_BIND_PAPER_CAN_NOT_REMOVE.getMsg());
        }

        if (checkTimeSubjectIsArrange(timeId)) {
            throw new KqException(ResponseCode.TIMES_IS_ARRANGE_CAN_NOT_REMOVE.getCode(),
                    ResponseCode.TIMES_IS_ARRANGE_CAN_NOT_REMOVE.getMsg());
        }

        // 检查是否绑定考场
        Integer countRoomBind = iTimeRoomService.lambdaQuery().
                eq(TimeRoom::getTaskId, taskId).
                eq(TimeRoom::getTimeId,timeId).
                eq(TimeRoom::getDelFlag, false).count();

        if (countRoomBind > 0) {
            throw new KqException(ResponseCode.TIMES_IS_BIND_ROOM_CAN_NOT_REMOVE.getCode(),
                    ResponseCode.TIMES_IS_BIND_ROOM_CAN_NOT_REMOVE.getMsg());
        }

        //删除批次
        LambdaUpdateWrapper<Time> timeUpdateWrapper = Wrappers.lambdaUpdate();
        timeUpdateWrapper.eq(Time::getId,timeId)
                .set(Time::getDelFlag,true);
        this.update(timeUpdateWrapper);

        //删除批次科目
        LambdaUpdateWrapper<TimeSubject> timeSubjectLambdaUpdateWrapper = Wrappers.lambdaUpdate();
        timeSubjectLambdaUpdateWrapper.eq(TimeSubject::getTaskId,taskId)
                .eq(TimeSubject::getTimeId,timeId)
                .eq(TimeSubject::getDelFlag,false)
                .set(TimeSubject::getDelFlag,true);
        iTimeSubjectService.update(timeSubjectLambdaUpdateWrapper);

        //推送数据到考试
        pushTimeParam(task,time,StringCodeEnum.PUSH_TYPE_DELETE.getCode());

    }

    @Override
    public List<TaskTimeInfoVO> getTimeInfo(String taskId) {
        //查询一个任务绑定的科目数
        LambdaQueryWrapper<TaskRoom> subjectQuery = Wrappers.lambdaQuery();
        subjectQuery.eq(TaskRoom::getTaskId,taskId).eq(TaskRoom::getDelFlag,Boolean.FALSE);
        //Integer roomNum = Optional.ofNullable(taskRoomMapper.selectCount(subjectQuery)).orElse(0);

        List<TaskTimeInfoVO> taskTimeInfoVOList = baseMapper.selectTimeInfo(taskId);
        taskTimeInfoVOList.stream().forEach(taskTimeVO -> {
            //List<SubjectInfoVO> subjectInfoVOList = baseMapper.selectTimeSubjectInfo(taskId,taskTimeVO.getTimeId());
            Integer count = baseMapper.selectTimeSubjectCount(taskId,taskTimeVO.getTimeId());
            /*subjectInfoVOList.stream().forEach(subjectInfoVO -> {
                if (StringUtils.isBlank(taskTimeVO.getSubjectNames())) {
                    taskTimeVO.setSubjectNames(subjectInfoVO.getSubjectName());
                    taskTimeVO.setSubjectIds(subjectInfoVO.getSubjectId());
                } else {
                    taskTimeVO.setSubjectNames(StringUtils.join(taskTimeVO.getSubjectNames(),",",subjectInfoVO.getSubjectName()));
                    taskTimeVO.setSubjectIds(StringUtils.join(taskTimeVO.getSubjectIds(),",",subjectInfoVO.getSubjectId()));
                }
            });*/
            taskTimeVO.setSubjectNum(count);
            //选择的考场
            Integer selectRoom = Optional.ofNullable(taskTimeVO.getRoomNum()).orElse(0);
            //Integer unBindRoom = roomNum - selectRoom;
            if(selectRoom < 0 ){
                selectRoom = 0;
            }
            taskTimeVO.setRoomNum(selectRoom);
        });
        return taskTimeInfoVOList.stream()
                .sorted(Comparator.comparing(TaskTimeInfoVO::getCode))
                .collect(Collectors.toList());
    }

    @Override
    public List<TimeInfoResultDTO> getTimeInfoResult(String taskCode, String placeCode) {
        return this.baseMapper.getTimeInfoResult(taskCode, placeCode);
    }

    @Override
    public List<Time> getByTaskId(String taskId) {
        QueryWrapper<Time> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(Time::getTaskId, taskId)
                .eq(Time::getDelFlag, false).orderByAsc(Time::getStartTime);
        return list(queryWrapper);
    }

    @Override
    public ExamMonitorCollectVO getExamMonitorData(String taskId, String timeId) {
        return this.baseMapper.getExamMonitorData(taskId, timeId);
    }

    @Override
    public List<OfficeRoomVO> getRoomListByTimeId(String taskId, String timeId) {
        return timeRoomMapper.getRoomListByTimeId(taskId, timeId);
    }

    /**
     * 插入批次科目表
     * @throws NestedBusinessException 插入失败，抛出异常
     */
    private void insertTimeSubject(List<TimeSubject> timeSubjectList) throws NestedBusinessException {
        if (!iTimeSubjectService.saveBatch(timeSubjectList)) {
            throw new NestedBusinessException("插入批次科目表失败");
        }
    }

    /**
     * 处理批次科目数据
     * @param timeParam 批次参数
     * @param time 批次
     * @return 批次科目数据
     */
    /*private List<TimeSubject> generateTimeSubject(TimeParam timeParam, Time time) {
        List<TimeSubject> timeSubjectList = new ArrayList<>();
        List<String> subjectIdList = timeParam.getSubjectIdList();
        String timeId = time.getId();
        String taskId = timeParam.getTaskId();
        subjectIdList.forEach(subjectId -> {
            TimeSubject timeSubject = new TimeSubject();
            timeSubject.setTaskId(taskId)
                    .setTimeId(timeId)
                    .setSubjectId(subjectId);
            timeSubjectList.add(timeSubject);
        });
        return timeSubjectList;
    }*/

    /**
     * 生成批次编号
     * @param timeParam 批次参数
     * @param timeList 所有批次
     * @return 批次对象
     */
    private Time generateTimeCode(TimeParam timeParam, List<Time> timeList) {
        //获取当前考试任务下最大的批次编号
        Optional<Time> timeOptional = timeList.stream()
                .max(Comparator.comparing(Time::getCode));
        //生成批次编号
        Time time = new Time();
        BeanUtils.copyProperties(timeParam, time);

        if (StringUtils.isNotBlank(timeParam.getTimeId())) {
            return time;
        }

        if (timeOptional.isPresent()) {
            //当前考试任务下已经存在考试批次
            Integer code = timeOptional.get().getCode();
            time.setCode(code + 1);
        } else {
            //当前考试任务下暂无考试批次
            time.setCode(1);
        }
        return time;
    }

    /**
     * 批次参数校验
     * @param timeParam 批次参数
     */
    private Time checkTimeParam(TimeParam timeParam) {
        //获取当前考试任务下所有批次
        QueryWrapper<Time> timeQueryWrapper = new QueryWrapper<>();
        timeQueryWrapper.lambda()
                .eq(Time::getTaskId, timeParam.getTaskId())
                .eq(Time::getDelFlag, false);
        List<Time> timeList = list(timeQueryWrapper);
        //校验批次名称是否重复
        if (!CollectionUtils.isEmpty(timeList)) {
            String name = timeParam.getName();
            String timeId = timeParam.getTimeId();
            boolean repeat = timeList.stream()
                    .anyMatch(time -> {
                        // 编辑时需要考虑到当前编辑的批次不要和数据库的自己进行比较
                        return time.getName().equals(name) && !Objects.equals(timeId, time.getId());
                    });
            if (repeat) {
                //当前考试任务下存在名称相同的考试批次
                throw new KqException(ResponseCode.TIMES_NAME_EXIST.getCode(),
                        ResponseCode.TIMES_NAME_EXIST.getMsg());
            }
        }
        //生成批次编号
        return this.generateTimeCode(timeParam, timeList);
    }

    /**
     * 插入批次表
     * @param time 考试批次
     * @throws NestedBusinessException 插入失败，抛出异常
     */
    private void insertTime(Time time) throws NestedBusinessException {
        if (!save(time)) {
            throw new NestedBusinessException("插入批次表失败");
        }
    }

    @Override
    public boolean isTimeCrossDay(String taskId) {
        return baseMapper.isTimeCrossDay(taskId) > 0 ? true : false;
    }

    @Override
    public boolean exists(String taskId) {

        Integer count = lambdaQuery()
                .eq(Time::getTaskId,taskId)
                .eq(Time::getDelFlag,false)
                .count();

        if (count > 0) {
            return true;
        }

        return false;
    }

    @Override
    public void pushTime(String taskId) {
        Task task = iTaskService.getById(taskId);
        if(task != null) {
            List<Time> list = super.lambdaQuery().eq(Time::getTaskId, taskId).list();
            if(list.size() > 0) {
                for (Time time : list) {
                    this.pushTimeParam(task, time, StringCodeEnum.PUSH_TYPE_INSERT.getCode());
                }
            } else {
                log.info("# 任务下没有批次:{}", taskId);
            }
        } else {
            log.info("# 任务不存在:{}", taskId);
        }
    }

    @Override
    public boolean hasTime(String taskId, String timeId) {
        return this.lambdaQuery().select(Time::getId)
                .eq(Time::getTaskId, taskId)
                .eq(Time::getId, timeId)
                .eq(Time::getDelFlag, false)
                .last("LIMIT 1")
                .oneOpt()
                .isPresent();
    }


    @Override
    public Time getByTimeSubjectId(String timeSubjectId) {
        return baseMapper.getByTimeSubjectId(timeSubjectId);
    }

    @Override
    public Integer countByTaskId(String taskId) {
        return this.lambdaQuery()
                .eq(Time::getTaskId, taskId)
                .eq(Time::getDelFlag, Boolean.FALSE)
                .count();
    }

    /**
     * 通过taskId查询
     * @param taskId
     * @return
     */
    @Override
    public List<Time> queryByTaskId(String taskId){
        return this.lambdaQuery().select(Time::getId)
                .eq(Time::getTaskId, taskId)
                .eq(Time::getDelFlag, false).list();
    }

    @Override
    public Map<String, String> getTimeMap(String taskId) {
        List<Time> list = this.lambdaQuery().eq(Time::getTaskId, taskId).eq(BaseEntity::getDelFlag, false).list();
        Map<String, String> map = new HashMap<>();
        for (Time time : list) {
            map.put(String.valueOf(time.getCode()), time.getId());
        }
        return map;
    }


    public File exportTime(String taskId){
        List<Time> list = this.lambdaQuery().eq(Time::getTaskId, taskId).eq(BaseEntity::getDelFlag, false).list();
        Task task = iTaskService.getTaskById(taskId);
        File file = null;
        if(CollectionUtil.isNotEmpty(list)){
            file = FileUtil.createTempFile(UUIDUtils.newSortUUID(),".dbf",true);
            try{
                DBFField[] pcDbf = arrangedResultExportUtil.getPcDBFField();
                DBFWriter writer = new DBFWriter(file, Charset.forName("GBK"));
                writer.setFields(pcDbf);
                list.stream().forEach(c -> {
                    Object[] data = new Object[pcDbf.length];
                    data[0] = task.getCode();
                    data[1] = String.valueOf(c.getCode().intValue());
                    data[2] = c.getName();
                    data[3] = DateTimeUtil.getDateTimeString(c.getStartTime());
                    data[4] = DateTimeUtil.getDateTimeString(c.getEndTime());
                    Duration duration = Duration.between(c.getStartTime(), c.getEndTime());
                    long minutes = duration.toMinutes() ;
                    data[5] = String.valueOf(minutes);
                    data[6] = "0";
                    data[7] = "1";
                    writer.addRecord(data);
                });
                writer.close();
                return file;
            } catch (Exception ex){
                if(file != null){
                    boolean flag = file.delete();
                    if(!flag) {
                        logger.error("删除文件失败");
                    }
                }

                throw new KqException(ResponseCode.ERROR_CREATE_PC_DBF.getCode(), "生成dbf文件失败");
            }
        } else {
            throw new KqException(ResponseCode.NOT_EXIST_BMK_DBF.getCode(), "没有编排数据，无法导出");
        }
    }
}
